/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 * \file
 * \brief MaCI - TaskCtrl Server interface header.
 * \author Antti Maula <antti.maula@tkk.fi>
 *
 * $Id: TaskCtrlServer.hpp,v 1.8 2009-10-15 11:18:23 mmatusia Exp $
 *
 */
#ifndef _MACI_INTERFACE_TASKCTRLSERVER_HPP_
#define _MACI_INTERFACE_TASKCTRLSERVER_HPP_
#include "MaCI.hpp"
#include "TaskCtrlData.hpp"
#include "sync.hpp"
#include "thread.hpp"
#include <list>


// Forward declare gimi::GIMI
namespace gimi {
  class GIMI;
  class GIMIMessage;
}

namespace MaCI {
  namespace TaskCtrl {

    // Forward declare CTaskCtrlServer
    class CTaskCtrlServer;


    /** Callback interface class for TaskCtrl server interface.
     *
     * This interface defines functions which can be used for
     * TaskCtrlClient callbacks. These functions are executed (more
     * detail per function basis) as new data arrives, and directly
     * from the context of the receiving thread. <b>Therefore, it is
     * important that the handling function is as simple and fast as
     * possible, as it will block the execution of the receiving
     * thread while executed.</b>
     */
    class CTaskCtrlServerCallback
    {
    public:

      CTaskCtrlServerCallback() {}
      virtual ~CTaskCtrlServerCallback() {}


      /** Handler function for TaskCtrlData event.
       *
       * This function is called when the TaskCtrlClient receives new
       * data from the server.
       *
       * \note <b>Keep this function simple & fast as it will block the 
       * data receiving thread while executing!</b>
       *
       * @param[in] aData       Constant reference to CTaskCtrlData element 
       *                        containing the received event.
       * @param[in] aDataSequence Sequence number of the received data. 
       *                        This should increment by one on each call.
       * @param[in] aTaskCtrlClient Reference to TaskCtrlClient 
       *                        instance which received this event.
       */
      virtual void OnTaskCtrlCommand(const CTaskCtrlData &aData, 
                                     const unsigned int aDataSequence,
                                     CTaskCtrlServer &aTaskCtrlServer) = 0;
    };
    

    /** MaCI - TaskCtrl Server interface
     * 
     * This class contains the methods and types for providing
     * the TaskCtrl service in the GIMnet.
     */
    class CTaskCtrlServer : public MaCI::CMaCI,
                            private gim::CSync,
                            private gim::CThread
    {
    public:
      /** Constructor.
       * 
       * Constructor of the TaskCtrlServer. This requires;
       * a pointer to Initialized and connected GIMI, minor
       * number of this interface (Used as GIMI minor number)
       *
       * @param[in] aMaCICtrlServerPtr Pointer to GIMI used for communication
       * @param[in] aInterfaceMinor Interface minor number. Usually
       * used to indicate the instance of devices of same type.
       * @param[in] aDescription User provided description about
       * service. This description will be appended after text
       * 'MaCI-TaskCtrlServer; ' in the GIMI service description
       * field.
       * @param[in] aInstanceName Specify Instance name here.
       * @param[in] aServiceType Initialize service type directly to given type.
       */
      CTaskCtrlServer(MaCICtrl::CMaCICtrlServer *aMaCICtrlServerPtr, 
                      const int aInterfaceMinor,
                      const std::string &aDescription = "",
                      const std::string &aInstanceName = "");
      

      /** Destructor.
       */
      ~CTaskCtrlServer();
 
      
      /** Return next incoming command in Queue.
       *
       * This function waits for new commands to arrive for a maximum
       * of 'aTimeout_ms' milliseconds. If a command is received, it
       * is stored to reference 'aData', and the function will return
       * KMaCIOK.
       *
       * @param[out] aData      Reference to CTaskCtrlData to be filled with
       *                        received information.
       * @param[out] aSource    Reference to message source information. This
       *                        is required for example for REPLY operations.
       * @param[in] aTimeout_ms Timeout in milliseconds to sleep waiting
       *                        for the operation to complete. If this
       *                        timeout exceeds and no commands are
       *                        received, this function returns KMaCITimeout.
       *
       * @param[in] aSkipQueued If this value is set to 'true', the
       *                        function will only return the last
       *                        received command and pop older ones
       *                        out from the queue. If this is set to
       *                        'false', all commands are received in
       *                        order. If parameter is undefined, 
       *                        default is 'false'.
       * @return                \c 'KMaCIOK' on succesfully received command.\n
       *                        \c 'KMaCITimeout' if timeout value exceeded.\n
       *                        \c 'KMaCIInvalidFormat' if the client received
       *                        a message of invalid format. It is safe to ignore this,
       *                        as it is only a notification for the application
       *                        that an invalid message was received. The event
       *                        is returned as it may help tracing down some
       *                        implementation problems.
       */
      MaCI::EMaCIError WaitCommand(CTaskCtrlData &aData,
                                   SMessageSource &aSource,
                                   const unsigned int aTimeout_ms,
                                   bool aSkipQueued = false);


       /** Send reply to client.
       * 
       * This function sends synchronous reply message to client.
       *
       * @param[in] aData       Reference to CTaskCtrlData. This data will be sent to
       *                        client for reply
       * @param[in] aInfo       Reference to replyInfo. Get this replyinfo from
       *                        WaitCommand.
       * @return                'KMaCIOK' when reply message succesfully sent.
       *                        Other errors returned when appropriate.
       *                        (See the MaCI::EMaCIError for description)
       * \see EMaCIError
       */
      MaCI::EMaCIError SendReply(const CTaskCtrlData &aData, 
                                 const SMessageSource &aSource);
      

      MaCI::EMaCIError SendTaskCtrlStatusEvent(const CTaskCtrlData &aTaskCtrlData);

     
    protected:
      /** Open device.
       *
       * Opens the device, basicly registers device to GIMI.
       *  
       * @return                Returns a value of type MaCI::EMaCIError. 
       *                        
       * \see EMaCIError
       */
      MaCI::EMaCIError DoOpen(void);
      
      
      /** Close device.
       *
       * Closes the device. Closes all GIMI registrations and queues.
       *
       * @return                Returns a value of type EMaCIError.
       *
       * \see EMaCIError
       */
      MaCI::EMaCIError DoClose(void);

    private:
      int ProcessMessage(const CTaskCtrlData &aMessage, const SMessageSource &aSource); ///< Process message func.
      int ThreadFunction(const int aThreadNumber); ///< Incoming data handler function
      std::list<std::pair< CTaskCtrlData, SMessageSource> > iCommandArray; ///< Queue for received commands NOT handled by thread.      

      
      bool iServerActive; ///< Is the server active? - flag
      std::string iServiceDescription; ///< User provided service description field.
      unsigned int iTaskCtrlSequenceNumber;
      uint16_t iNextMajor;
    };

  }
}


#endif //_MACI_INTERFACE_TASKCTRLSERVER_HPP_
